package sqlx

import (
	"context"
	"database/sql"
)

// ISql 为对外暴露的主要接口，该接口由 Engine 实现。
type ISql interface {
	// Query 参数<querySql>是查询类的SQL语句，<args>是SQL语句的参数。
	QueryX(querySql string, args ...interface{}) (*Rows, error)
	// QueryRow 参数<querySql>是查询类的SQL语句，<args>是SQL语句的参数。
	QueryRowX(querySql string, args ...interface{}) *Row
	// Exec 增、删、改操作的接口。
	//  参数<querySql>是查询类的SQL语句，<args>是SQL语句的参数。
	Exec(querySql string, args ...interface{}) (sql.Result, error)
	// Take 查询一条记录，并将结果扫描进 <pointer>
	//  参数<pointer>可以是struct/*struct。
	//  参数<querySql>是查询类的SQL语句，<args>是SQL语句的参数。
	Take(pointer interface{}, querySql string, args ...interface{}) error
	// Select 查询多条记录，并将查询结果扫描进 <pointer>
	//  参数<pointer>可以是[]struct/*[]struct。
	//  参数<querySql>是查询类的SQL语句，<args>是SQL语句的参数。
	Select(pointer interface{}, querySql string, args ...interface{}) error
	PrepareX(query string) (*Stmt, error)
	// Rebind 绑定 querySql 语句。
	Rebind(querySql string) string
	// DriverName 获取当前处于连接状态的 *sql.DB 的驱动名称。
	DriverName() string
}

// Ext 是一个可以绑定，查询和执行的联合接口，供 NamedQuery 和 NamedExec 使用。
type Ext interface {
	IBind
	IQuery
	IExecute
}

// IQuery 查询操作的接口。// 仅由 *qStmt实现了这个接口
type IQuery interface {
	Query(query string, args ...interface{}) (*sql.Rows, error)
	QueryX(query string, args ...interface{}) (*Rows, error)
	QueryRowX(query string, args ...interface{}) *Row
}

// IExecute 是 MustExec 和 LoadFile 使用的接口。
type IExecute interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
}

// IBind 是可以绑定查询（Tx，DB）的接口。
type IBind interface {
	DriverName() string
	Rebind(string) string
	BindNamed(string, interface{}) (string, []interface{}, error)
}

// IPrepare 是 PrepareX 使用的接口。
type IPrepare interface {
	Prepare(query string) (*sql.Stmt, error)
}

// ColScanner 是MapScan和SliceScan使用的接口。
type ColScanner interface {
	Columns() ([]string, error)
	scan(pointer ...interface{}) error
	Err() error
}

// IRow 是 ColScanner 和 io.Closer 的联合接口。
type IRow interface {
	Columns() ([]string, error)
	Scan(...interface{}) error
	Err() error
	Next() bool
	Close() error
}

//==================== Context 相关的接口 ====================================//

// IQueryContext 是 GetContext 和 SelectContext 使用的接口
type IQueryContext interface {
	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
	QueryXCtx(ctx context.Context, query string, args ...interface{}) (*Rows, error)
	QueryRowXCtx(ctx context.Context, query string, args ...interface{}) *Row
}

// IPrepareContext 是 PreparexContext 使用的接口。
type IPrepareContext interface {
	PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
}

// IExecuteContext 是 MustExecContext 和 LoadFileContext 使用的接口
type IExecuteContext interface {
	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
}

// 是 IPrepareContext 和 IBind 的联合接口，要求能够准备具有上下文的命名语句 (因为必须确定绑定类型)。
type namedPreparerContext interface {
	IPrepareContext
	IBind
}

// ExtContext 是一个联合接口，可以与NamedQueryContext和NamedExecContext使用的Context绑定，查询和执行。
type ExtContext interface {
	IBind
	IQueryContext
	IExecuteContext
}
